home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CICA 1993 April
/
CICA MS Windows - April 1993.iso
/
unzipped
/
programr
/
3dlib17f
/
rtobj.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-03-15
|
34KB
|
834 lines
(******************************************************************************
* rtObj *
* please notice - *
* this unit includes both the object3d unit, and the superobj unit, *
* and it is used with no reference to the WWToolKit window GUI library, *
* uses project3, instead of prjWind (It does, however, support OWL) *
******************************************************************************)
Unit rtObj;
(*******************************************************************************
* 3D Objects *
* ---------- *
* *
* A 3D object is a collection of points and lines in the 3D universe, *
* that represent the body we want to draw on the screen. *
* A 3D object is allways centered around point (0, 0, 0) in the 3D universe. *
* (Its center of gravity assuming it is has a uniform weight distribution *
* is in point (0, 0, 0) *
* At any moment during the object's life, we know it's distance from the *
* origin, And it's rotation using reveres rotation CTM. *
* *
* 3D Object methods: *
* constructor Open *
* destructor CloseMe *
* procedures: Rotate, Scale, Move, Show, Hide, Load, Save *
* SetToOrigin, Paint *
* *
*******************************************************************************)
interface
uses
{$ifdef windows}
winTypes
,winProcs
{$else}
graph
{$endif}
,Ctm3d
,hdr3d
,project3
;
type
f_real = file of real;
{===================================================================}
{ Base object is the base class for 3D-objects. some functions }
{ are dummy virtual do-nothing, which are are implemented only for }
{ the descendend objects derived from BaseObject }
{===================================================================}
BaseObjectPtr = ^BaseObject;
BaseObject = object
MyCtm : Ctm; { This CTM applied to the object gives the }
{ objects Position after transformations }
Name : String; { Identifies the object }
myColor : word; { Main color for the object }
Location : point3d; { Central of gravity in real space }
scrPntUpdt : boolean; { True if screen points updated }
constructor open(myName : string; color : word);
destructor CloseMe; virtual;
{$ifdef windows}
procedure show(dc : hdc); virtual;
procedure hide(dc : hdc); virtual;
procedure paint(dc : hdc); virtual; {in specified color}
{$else}
procedure show; virtual;
procedure hide; virtual;
procedure paint; virtual; {in specified color}
{$endif}
procedure updateScreenPoints; virtual; {transform object 3D -> 2D}
procedure move(axis : axisType; by : real); virtual;
procedure translate(dx, dy, dz : integer); virtual;
{multy dimentional move in 1 call}
procedure scale(axis : axisType; factor : real); virtual;
procedure allScale(sx, sy, sz : real); virtual;
{multy dimentional scale in 1 call}
procedure rotate(axis : axisType; deg : real); virtual;
procedure goto3dPos(x, y, z : real); virtual; {translate to absolute place}
procedure setToOrigin; virtual;
{translate to 0,0,0, update points, and set myCtm to unit}
procedure calcLocation; virtual; {set Location to central gravity}
procedure deleteTransform; virtual; {set MyCtm to unit}
function load : word; virtual; {from disk}
function save : word; virtual; {to disk}
procedure writeMe(var elementFile : f_real); virtual; {to disk .. without opening file..}
procedure readMe(var elementFile : f_real); virtual;
end;
{===================================================================}
{ Obj3d is an object which represents a 3-D object with a poligon }
{ mesh. }
{===================================================================}
Obj3dPtr = ^Obj3d;
Obj3d = object(BaseObject)
Points : array[1..MaxPoints] of point3d;
Lines : array[1..MaxLines] of Line3d;
scrPoints : array[1..MaxPoints] of screenPoints;
NumOfLines : integer;
NumOfPoints : integer;
ReverseRot : Ctm; { Saves only the reverse rotations }
unReverseRot: Ctm; { reverse of the above}
constructor open(myName : string; ref : point3d; color : word);
destructor CloseMe; virtual;
{$ifdef windows}
procedure paint(dc : hdc); virtual; {in specified color}
{$else}
procedure paint; virtual; {in specified color}
{$endif}
procedure updateScreenPoints; virtual; {transform object 3D -> 2D}
procedure calcLocation; virtual; {set Location to central gravity}
procedure setToOrigin; virtual;
procedure writeMe(var elementFile : f_real); virtual;
procedure readMe(var elementFile : f_real); virtual;
end;
const
maxSubObjects = 15;
type
complexObjPtr = ^complexObj;
ComplexObj = object(BaseObject)
childs : array [1..maxSubObjects] of obj3dPtr;
ctms : array [1..maxSubObjects] of ctm;
numOfChilds : integer; {counter of # of obj3d childs}
constructor open(myName : string; color : word);
destructor closeMe; virtual;
procedure updateScreenPoints; virtual;
procedure writeMe(var elementFile : f_real); virtual;
procedure readMe(var elementFile : f_real); virtual;
procedure calcLocation; virtual;
{$ifdef WINDOWS}
procedure paint(dc : hdc); virtual;
{$else}
procedure paint; virtual;
{$endif}
procedure move(axis : axisType; by : real); virtual;
procedure rotate(axis : axisType; deg : real); virtual;
procedure scale(axis : axisType; factor : real); virtual;
function addSubObject(myName : string; refPoint : point3d) : word;
function getChildPtr(index : integer) : obj3dPtr;
procedure rotateChild(child : integer; axis : axisType;
deg : real);
procedure scaleChild(child : integer; axis : axisType;
factor : real);
procedure moveChild(child : integer; axis : axisType;
by : real);
end;
implementation
{%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%}
{ BaseObject implementation }
{%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%}
(*******************************************************************************
* BaseObject.Open *
*******************************************************************************)
constructor BaseObject.Open;
begin
name := myName;
myColor := color;
location := ZeroPoint;
MyCtm.SetUnit;
end; {baseObject.open}
(*******************************************************************************
* BaseObject.CloseMe *
*******************************************************************************)
destructor BaseObject.CloseMe;
begin
{ I'm here so my children will Close-themselfs properly }
end; {baseObject.closeMe}
(*******************************************************************************
* BaseObject.move *
*******************************************************************************)
procedure BaseObject.move(axis : axisType; by: real);
begin
case axis of
x : begin
myCtm.translateX(by);
location.x :=location.x+by;
end;
y : begin
myCtm.translateY(by);
location.y :=location.y+by;
end;
z : begin
myCtm.translateZ(by);
location.z :=location.z+by;
end;
end; {case}
scrPntUpdt := False;
end; {BaseObject.move}
(*******************************************************************************
* BaseObject.translate *
*******************************************************************************)
procedure BaseObject.translate(dx, dy, dz : integer);
begin
myCtm.translate(dx,dy,dz);
location.x :=location.x+dx;
location.y :=location.y+dy;
location.z :=location.z+dz;
scrPntUpdt := False;
end; {BaseObject.translate}
{use this routine when you know you need to translate more then one axis
before painting, you will use only one call, which will probably be
faster, and make your program easier to read, and maintain}
(*******************************************************************************
* BaseObject.show *
*******************************************************************************)
procedure BaseObject.show;
{$ifdef windows}
var
myPen, oldPen : HPen;
{$endif}
begin
{$ifdef WINDOWS}
myPen := getStockObject(black_Pen);
oldPen := selectObject(dc, myPen);
paint(dc);
selectObject(dc, oldPen);
deleteObject(myPen);
{$else}
setColor(myColor);
paint;
{$endif}
end; {baseObject.show}
(*******************************************************************************
* BaseObject.hide *
*******************************************************************************)
procedure BaseObject.hide;
{$ifdef windows}
var
myPen, oldPen : HPen;
{$endif}
begin
{$ifdef windows}
myPen := getStockObject(white_Pen);
oldPen := selectObject(dc, myPen);
paint(dc); {at this color}
selectObject(dc, oldPen);
deleteObject(myPen);
{$else}
setColor(0); {backGround}
paint; {at this color}
{$endif}
end; {baseObject.hide}
(*******************************************************************************
* BaseObject.Paint *
*******************************************************************************)
procedure BaseObject.Paint;
begin
if (not(scrPntUpdt)) then
updateScreenPoints;
{ alas, BaseObject cannot really paint becuase it does not have }
{ screen points (what a shame ...) }
end; {baseObject.paint}
(*******************************************************************************
* BaseObject.UpdateScreenPoints *
*******************************************************************************)
procedure BaseObject.UpdateScreenPoints;
begin
scrPntUpdt := True; { Have no screen points or any other points, so }
{ points are already updated (I think) }
end; {updateScreenPoints}
(*******************************************************************************
* BaseObject.scale *
*******************************************************************************)
procedure BaseObject.scale(axis : axisType; factor : real);
begin
myCtm.translate(-location.x,-location.y,-location.z);
case axis of
x : myCtm.scaleX(factor);
y : myCtm.scaleY(factor);
z : myCtm.scaleZ(factor);
end; {scale}
myCtm.translate(location.x,location.y,location.z);
scrPntUpdt := False;
end; {baseObject.scale}
(*******************************************************************************
* BaseObject.allScale *
*******************************************************************************)
procedure BaseObject.allScale(sx,sy,sz : real);
begin
myCtm.translate(-location.x, -location.y, -location.z);
myCtm.scale(sx,sy,sz);
myCtm.translate(location.x, location.y, location.z);
scrPntUpdt := False;
end; {allScale}
{call this routine to scale more then one axis at a time, with a single call}
(*******************************************************************************
* BaseObject.goto3dPos *
*******************************************************************************)
procedure BaseObject.goto3dPos;
begin
translate(round(x - location.x), round(y - location.y)
, round(z - location.z));
end; {baseObject.goto3dPos}
(*******************************************************************************
* BaseObject.setToOrigin *
*******************************************************************************)
procedure BaseObject.setToOrigin;
begin
goto3dPos(0, 0, 0);
myCtm.setUnit;
location := zeroPoint;
end; {BaseObject.setToOrign}
(*******************************************************************************
* BaseObject.CalcLocation *
*******************************************************************************)
procedure BaseObject.CalcLocation;
begin
location := zeroPoint; { What else could it be when there are no points ?}
end; {baseObject.calcLocation}
(*******************************************************************************
* BaseObject.deleteTransform *
*******************************************************************************)
procedure BaseObject.deleteTransform;
begin
myCtm.setUnit;
scrPntUpdt := false;
end; {baseObject.deleteTransform}
(******************************************************************************
* BaseObject.rotate *
******************************************************************************)
procedure BaseObject.rotate;
begin
myCtm.translate(-location.x,-location.y,-location.z);
case axis of
x : myCtm.rotateX(deg);
y : myCtm.rotateY(deg);
z : myCtm.rotateZ(deg);
end; {case}
myCtm.translate(location.x,location.y,location.z);
{rotation means : go to origin (translate -location),
rotate (rotate axis degrees),
go to prev pos (translate location);
}
scrPntUpdt := False;
end; {BaseObject.rotate, see interface for comments}
(******************************************************************************
* baseObject.load *
******************************************************************************)
function baseObject.load;
var
elementFile : f_real;
errC : word;
begin
{$i-} {supposed to be so, just making sure}
assign(elementFile,name);
reset(elementFile); {o.k. open it}
errC := ioResult;
load := errC;
if (errC = 0) then begin
readMe(elementFile);
errC := ioResult;
load := errC;
close(elementFile);
calcLocation;
scrPntUpdt := false;
end; {if}
end; { baseObject.load}
(******************************************************************************
* baseObject.save *
******************************************************************************)
function baseObject.save;
var
elementFile : f_real;
errC : word;
begin
{$i-} {supposed to be so, just making sure}
assign(elementFile,name);
rewrite(elementFile); {o.k. open it}
errC := ioResult;
save := errC;
if (errC = 0) then begin
writeMe(elementFile);
errC := ioResult; save := errC;
close(elementFile);
end; {if}
end; {baseObject.save}
(******************************************************************************
* baseObject.writeMe *
******************************************************************************)
procedure baseObject.writeMe;
begin
{override by descendents }
end; {baseObject.writeMe}
(******************************************************************************
* baseObject.readMe *
******************************************************************************)
procedure baseObject.readMe;
begin
{override by descendents }
end; {baseObject.readMe}
{%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%}
{ Obj3d implementation }
{%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%}
(*******************************************************************************
* Obj3d.open *
*******************************************************************************)
constructor Obj3d.open;
begin
BaseObject.Open(myName, color);
scrPntUpdt := False; {not calculated yet}
numOfLines := 0;
numOfPoints := 0;
myCtm.setUnit; {initialize to unit matrix}
reverseRot.setUnit;
unReverseRot.setUnit;
end; {Obj3d.open}
(*******************************************************************************
* Obj3d.CloseMe *
*******************************************************************************)
destructor Obj3d.CloseMe;
begin
end; {Obj3d.Close}
(*******************************************************************************
* Obj3d.updateScreenPoints *
*******************************************************************************)
procedure Obj3d.updateScreenPoints;
var i : integer;
p : point3d;
begin
for i := 1 to numOfPoints do begin
myCtm.transform(p,points[i]); {transform by ctm}
calcPoint(p, scrPoints[i]);
end; {for}
scrPntUpdt := True; {make sure for next time..}
{make all points ready}
end; {obj3d.updateScreenPoints}
(*******************************************************************************
* Obj3d.paint *
*******************************************************************************)
procedure Obj3d.paint;
{do the actual painting here}
var
i : integer;
begin
if ((numOfPoints = 0) or (numOfLines = 0)) then exit;
if (not(scrPntUpdt)) then
updateScreenPoints;
for i := 1 to numOfLines do begin
{$ifdef windows}
moveTo(dc, scrPoints[lines[i].fromP].sX, scrPoints[lines[i].fromP].sY);
lineTo(dc, scrPoints[lines[i].toP].sX, scrPoints[lines[i].toP].sY );
{$else}
line(scrPoints[lines[i].fromP].sX,
scrPoints[lines[i].fromP].sY,
scrPoints[lines[i].toP].sX,
scrPoints[lines[i].toP].sY);
{$endif}
end; { for }
{it should be noted that calcPoint has to convert points to integers}
end; {obj3d.paint}
(******************************************************************************
* obj3d.readMe *
******************************************************************************)
procedure obj3d.readMe;
var
tmp1,tmp2 : real;
i,j : byte;
begin
read(elementFile, tmp1);
numOfPoints := trunc(tmp1);
for j := 1 to numOfPoints do begin
read(elementFile, points[j].x);
read(elementFile, points[j].y);
read(elementFile, points[j].z);
end; {for}
read(elementFile, tmp1);
numOfLines := trunc(tmp1);
for j := 1 to numOfLines do begin
read(elementFile, tmp1, tmp2);
lines[j].fromP := trunc(tmp1);
lines[j].toP := trunc(tmp2);
end; {for}
end; {obj3d.readMe}
(******************************************************************************
* obj3d.writeMe *
******************************************************************************)
procedure obj3d.writeMe;
var
tmp1,tmp2 : real;
i,j : byte;
begin
tmp1 := numOfPoints;
write(elementFile, tmp1);
for j := 1 to numOfPoints do begin
write(elementFile, points[j].x);
write(elementFile, points[j].y);
write(elementFile, points[j].z);
end; {for}
tmp1 := numOfLines;
write(elementFile, tmp1);
for j := 1 to numOfLines do begin
tmp1 := lines[j].fromP;
tmp2 := lines[j].toP;
write(elementFile, tmp1, tmp2);
end;
end; {obj3d.writeMe}
(*******************************************************************************
* obj3d.calcLocation *
*******************************************************************************)
procedure obj3d.calcLocation;
var
ce : point3d;
p : point3d;
i : integer;
begin
ce := zeroPoint; { (0, 0, 0) -> ce }
for i := 1 to numOfPoints do begin
myCtm.transform(p, points[i]);
ce.x := ce.x + p.x;
ce.y := ce.y + p.y;
ce.z := ce.z + p.z;
end; {for}
location.x := ce.x / numOfPoints;
location.y := ce.y / numOfPoints;
location.z := ce.z / numOfPoints;
end; {obj3d.calcLocation}
(*******************************************************************************
* Obj3d.setToOrigin *
*******************************************************************************)
procedure Obj3d.setToOrigin;
var
i : integer;
p : point3d;
begin
goto3dPos(0, 0, 0);
for i := 1 to numOfPoints do begin
myCtm.transform(p, points[i]);
points[i] := p;
end; {for}
scrPntUpdt := False; (** Instead of that THING above **)
myCtm.setUnit;
location := zeroPoint;
end; {BaseObject.setToOrign}
(*******************************************************************************
* ComplexObj.Open *
*******************************************************************************)
constructor ComplexObj.Open;
begin
BaseObject.Open(myName, color);
numOfChilds := 0;
end; {complexObj.open}
(*******************************************************************************
* ComplexObj.CloseMe *
*******************************************************************************)
destructor ComplexObj.CloseMe;
var
i : integer;
begin
for i := 1 to numOfChilds do
dispose(childs[i],closeMe);
baseObject.closeMe;
end; {complexObj.closeMe}
(*******************************************************************************
* ComplexObj.addSubObject *
*******************************************************************************)
function ComplexObj.addSubObject;
var
ret_code : word;
begin
if (numOfChilds >= maxSubObjects) then begin
addSubObject := 255; {signal error}
exit;
end;
inc(numOfChilds);
childs[numOfChilds] := new(obj3dPtr, open(myName, zeroPoint, myColor));
ret_code := childs[numOfChilds]^.load;
if (ret_code = 0) then begin
with refPoint do
childs[numOfChilds]^.translate(round(x),
round(y), round(z));
ctms[numOfChilds].copy(childs[numOfChilds]^.myCtm);
end; {if ret_c..}
addSubObject := ret_code;
end; {complexObj.addSubObject}
(*******************************************************************************
* complexObj.updateScreenPoints *
*******************************************************************************)
procedure complexObj.updateScreenPoints;
var
i : integer;
begin
for i := 1 to numOfChilds do begin
childs[i]^.myCtm.multiply_2(ctms[i], myCtm);
childs[i]^.updateScreenPoints;
end;
scrPntUpdt := True;
end; {complexObj.updateScreenPoints}
(*******************************************************************************
* complexObj.getChildPtr *
*******************************************************************************)
function complexObj.getChildPtr;
begin
getChildPtr := childs[index];
end; {complexObj.getChildPtr}
(*******************************************************************************
* ComplexObj.rotateChild *
*******************************************************************************)
procedure ComplexObj.rotateChild;
begin
with childs[child]^ do begin
myCtm.copy(ctms[child]);
rotate(axis, deg);
ctms[Child].copy(MyCtm);
myCtm.Multiply(Self.myCtm);
end;
end; {complexObj.rotateChild}
(*******************************************************************************
* ComplexObj.scaleChild *
*******************************************************************************)
procedure ComplexObj.scaleChild;
begin
with childs[child]^ do begin
myCtm.copy(ctms[child]);
scale(axis, factor);
ctms[Child].copy(MyCtm);
myCtm.Multiply(Self.myCtm);
end;
end; {complexObj.scaleChild}
(*******************************************************************************
* ComplexObj.moveChild *
*******************************************************************************)
procedure ComplexObj.moveChild;
begin
with childs[child]^ do begin
myCtm.copy(ctms[child]);
move(axis, by);
ctms[Child].copy(MyCtm);
myCtm.Multiply(Self.myCtm);
end;
end; {complexObj.moveChild}
(******************************************************************************
* complexObj.paint *
******************************************************************************)
procedure complexObj.paint;
var
i : integer;
begin
if (not(scrPntUpdt)) then
updateScreenPoints;
for i := 1 to numOfChilds do
{$ifdef WINDOWS}
childs[i]^.paint(dc);
{$else}
childs[i]^.paint;
{$endif}
end; {complexObj.paint}
(******************************************************************************
* complexObj.writeMe *
******************************************************************************)
procedure complexObj.writeMe;
var
i : integer;
r : real;
begin
r := 0.0 + numOfChilds;
write(elementFile, r);
for i := 1 to numOfChilds do
childs[i]^.writeMe(elementFile); {let all the kids write themselvs}
end; {complexObj.writeMe}
(******************************************************************************
* complexObj.readMe *
******************************************************************************)
procedure complexObj.readMe;
var
i : integer;
r : real;
begin
read(elementFile, r);
numOfChilds := round(r);
for i := 1 to numOfChilds do begin
childs[i] := new(Obj3dPtr, Open('Child', ZeroPoint, myColor));
childs[i]^.readMe(elementFile);
childs[i]^.calcLocation;
ctms[i].setUnit;
end; {for}
end; {complexObj.readMe}
(******************************************************************************
* complexObj.calcLocation *
******************************************************************************)
procedure complexObj.calcLocation;
var
i : integer;
begin
location := zeroPoint;
for i := 1 to numOfChilds do
with childs[i]^ do begin
calcLocation;
self.location.x := location.x + self.location.x;
self.location.y := location.y + self.location.y;
self.location.z := location.z + self.location.z;
end; {with}
with location do begin
x := x / numOfChilds;
y := y / numOfChilds;
z := z / numOfChilds;
end; {with..}
end; {complexObj.calclocation}
(******************************************************************************
* complexObj.move *
******************************************************************************)
procedure complexObj.move;
var
i : integer;
begin
(* for i := 1 to numOfChilds do
with childs[i]^ do
case axis of
x : location.x := location.x + by;
y : location.y := location.y + by;
z : location.z := location.z + by;
end; {case} *)
baseObject.move(axis, by);
end; {complexObj.move}
(******************************************************************************
* complexObj.rotate *
******************************************************************************)
procedure complexObj.rotate;
var
i : integer;
sint, cost : real;
begin
(* cost := cos(deg / 180.0 * 3.1415926535897932385);
sint := sin(deg / 180.0 * 3.1415926535897932385);
for i := 1 to numOfChilds do
with childs[i]^ do
case axis of
x : begin
location.y := location.y * cost -
location.z * sint;
location.z := location.y * sint +
location.z * cost;
end; {x}
y : begin
location.x := location.x * cost +
location.z * sint;
location.z := location.z * cost -
location.x * sint;
end; {y}
z : begin
location.x := location.x * cost -
location.y * sint;
location.y := location.y * cost +
location.x * sint;
end; {z}
end; {case} *)
baseObject.rotate(axis, deg);
end; {complexObj.rotate}
(******************************************************************************
* complexObj.scale *
******************************************************************************)
procedure complexObj.scale;
var
i : integer;
begin
(* for i := 1 to numOfChilds do
with childs[i]^ do
case axis of
x : location.x := location.x * factor;
y : location.y := location.y * factor;
z : location.z := location.z * factor;
end; {case} *)
baseObject.scale(axis, factor);
end; {complexObj.scale}
(******************************************************************************
* end. *
******************************************************************************)
end.